﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.Composition;
using EFBase;
using MF_Base;
using MFTool;
using System.Text;
using MF_Base.Model;
using UIBase;
using System.Linq.Expressions;
using System.Reflection;

namespace AutoUI.Areas.ConfigUIDef.Controllers
{
    [Export]
    public class FormController : BaseController
    {
        #region 表单列表
        public ActionResult List()
        {
            return View();
        }

        public JsonResult Delete()
        {
            string ids = QueryString("ids");
            var idArr = ids.Split(',');
            UnitOfWork.Delete<FormConfig>(a => idArr.Contains(a.Id));
            UnitOfWork.Commit();
            return Json("删除成功");
        }
        #endregion

        #region 数据表的类实体(Entity)
        public ActionResult EntityList()
        {
            return View();
        }

        public JsonResult GetEntityList()
        {
            string tableName = QueryString("TableName").ToLower();
            var names = WebConfigHelper.GetConnSettingNames();
            List<dynamic> list = new List<dynamic>();
            var exsitEntityFullNames = UnitOfWork.Get<FormConfig>().Select(a => a.EntityFullName);

            //根据entityfullname筛选，同时排除已经定义的实体
            foreach (var name in names)
            {
                string baseEntityName = "Entity";
                list.AddRange(CommonHelper.GetClassFullNames(name, baseEntityName)
                    .Where(a => (string.IsNullOrEmpty(tableName) ? true : a.GetValue("ClassName").ToLower().Contains(tableName)))
                    .Select(a => new
                    {
                        ModuleName = name,
                        EntityFullName = a.GetValue("FullName"),
                        TableName = a.GetValue("ClassName"),
                        Name = a.GetValue("Description")
                    }));
            }

            return Json(list);
        }
        #endregion

        #region 表单(Form)

        public JsonResult AddForm()
        {
            var dataStr = QueryString("data");
            FormConfig cForm = dataStr.JsonToObject<FormConfig>();
            cForm.Id = GuidHelper.CreateTimeOrderID();
            cForm.MainTypeFullId = CommonStr.MainTypeTreeRootID + "." + cForm.ModuleName;
            string defaultCodeName = cForm.EntityFullName.Replace('.', '_');
            if (!UnitOfWork.IsExist<FormConfig>(a => a.ModuleName == cForm.ModuleName && a.TableName == cForm.TableName))
            {
                cForm.UICode = defaultCodeName;//xx_xxx_xx
            }
            else
            {
                cForm.UICode = cForm.Id;
            }

            UnitOfWork.Add(cForm);
            bool b = UnitOfWork.Commit();
            return Json(b);
        }

        [ValidateInput(false)]
        public JsonResult SaveForm()
        {
            var dic = Request.Form["formData"].JsonToObject<Dictionary<string, object>>();
            string uiCode = dic.GetValue("UICode");
            string id = dic.GetValue("Id");
            if (UnitOfWork.IsExist<FormConfig>(a => a.UICode == uiCode && a.Id != id))
            {
                throw new BusinessException("已经存在编号为{0}的表单".ReplaceArg(dic.GetValue("UICode")));
            }

            if (string.IsNullOrEmpty(dic.GetValue("Id")))
            {
                FormConfig cForm = ConvertHelper.ConvertToObj<FormConfig>(dic);
                cForm.Id = GuidHelper.CreateTimeOrderID();
                UnitOfWork.Add(cForm);
            }
            else
            {
                FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(dic.GetValue("Id"));
                ConvertHelper.UpdateEntity(cForm, dic, true, "CtrlSetting", "LayOutSetting", "GroupSetting");
                UnitOfWork.UpdateEntity(cForm);
            }

            bool b = UnitOfWork.Commit();
            return Json(b);
        }

        public JsonResult GetForm()
        {
            string id = QueryString("id");
            id.CheckNotNullOrEmpty("id");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(id);
            cForm.CheckNotNull("FormConfig");
            return Json(cForm);
        }
        #endregion

        #region 控件组
        public ActionResult CtrlGroup()
        {
            return View();
        }

        public JsonResult SaveGroupSetting(string formId, string data)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            cForm.GroupSetting = data;
            bool res = UnitOfWork.Commit();
            return Json(res);
        }

        public JsonResult GetGroupSetting(string formId)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            return Json(JsonHelper.JsonRegex(cForm.GroupSetting));
        }
        #endregion

        #region 属性/字段控件(Ctrl)
        public ActionResult Ctrl()
        {
            string formId = QueryString("Id");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");

            ViewBag.CtrlGroup = "[]";
            if (!string.IsNullOrEmpty(cForm.GroupSetting))
                ViewBag.CtrlGroup = cForm.GroupSetting;

            var fieldTypeList = SqlHelper.SQlCommonServerTypeList().Select(a => new { text = a, value = a });
            ViewBag.FieldType = fieldTypeList.ToJson();

            //根据EF的机制必须调用一下相关函数,才能将模型同步至数据库
            if(!string.IsNullOrEmpty(cForm.EntityFullName))
            {
                string entityFullName = cForm.EntityFullName;
                string projName = cForm.ModuleName;
                var entityType = ReflectionHelper.GetTypeBy(projName, entityFullName);
                var getMethod = typeof(EFBase.UnitOfWork).GetMethod("GetByKey", BindingFlags.Instance | BindingFlags.Public);
                getMethod.CheckNotNull("UnitOfWork中的GetByKey方法未找到或者不可访问");
                getMethod = getMethod.MakeGenericMethod(entityType);
                var res = getMethod.Invoke(UnitOfWork, new object[] { "" });
            }

            return View();
        }
        public JsonResult GetList()
        {
            int totalCount = 0;
            string uiCode = QueryString("UICode");

            int pageId = Convert.ToInt32(QueryString("page"));
            int pageSize = Convert.ToInt32(QueryString("rows"));
            string mainType = QueryString("MainType");
            string moduleName = QueryString("ModuleName");
            Expression<Func<FormConfig, bool>> condition = null;
            if (!string.IsNullOrEmpty(mainType))
            {
                condition = a => a.MainTypeFullId.Contains(mainType);
            }
            else if (!string.IsNullOrEmpty(moduleName))
            {
                condition = a => a.ModuleName == moduleName;
            }

            if (!string.IsNullOrEmpty(uiCode))
            {
                condition = a => a.UICode.Contains(uiCode);
            }

            IEnumerable<FormConfig> baseForms = UnitOfWork.
                GetByPage<FormConfig, string>(out totalCount, pageSize, pageId, a => a.Id, false, condition);
            return Json(new { rows = baseForms, total = totalCount });
        }
        public JsonResult GetCtrlList()
        {
            string id = QueryString("formId");
            FormConfig fc = UnitOfWork.GetByKey<FormConfig>(id);
            fc.CheckNotNull("FormConfig");
            return Json(fc.GetCtrlAttrList());
        }
        public JsonResult SaveCtrl(string formId)
        {
            var dicList = QueryString("rows").JsonToDictionaryList();
            if (dicList.Count() != dicList.Select(a => a.GetValue("FieldName")).Distinct().Count())
            {
                throw new BusinessException("字段名不能重复");
            }

            FormConfig fc = UnitOfWork.GetByKey<FormConfig>(formId);
            fc.CheckNotNull("FormConfig");

            GeneralDataTable(fc.TableName, fc.ModuleName, dicList);

            fc.UpdateCtrl(dicList);
            UnitOfWork.UpdateEntity(fc);
            bool res = UnitOfWork.Commit();
            return Json(res);
        }

        public JsonResult DeleteCtrl(string formId, string fieldNames)
        {
            string id = QueryString("formId");
            FormConfig fc = UnitOfWork.GetByKey<FormConfig>(id);
            fc.CheckNotNull("FormConfig");
            var ctrlList = fc.GetCtrlAttrList();
            var fieldCtrlList = fieldNames.Split(',');
            string sql = "alter table {0} drop column {1}";
            SqlHelper sqlHelper = SqlHelper.CreateSqlHelper(fc.ModuleName);
            List<dynamic> resInfos = new List<dynamic>();
            foreach (var fieldCtrl in fieldCtrlList)
            {
                try
                {
                    sqlHelper.ExcuteNoQuery(sql.ReplaceArg(fc.TableName, fieldCtrl));
                    resInfos.Add(new { Success = true, FieldName = fieldCtrl, Info = "" });
                }
                catch(Exception ex)
                {
                    resInfos.Add(new { Success = false, FieldName = fieldCtrl, Info = ex.Message });
                }
            }

            return Json(resInfos);
        }

        /// <summary>
        /// 根据表单配置生成数据库表
        /// </summary>
        /// <returns></returns>
        private void GeneralDataTable(string tableName, string moduleName, List<Dictionary<string,object>> ctrlList)
        {
            //生成表的sql
            string tableSql = @"IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{0}]') AND type in (N'U'))
BEGIN
CREATE TABLE [{0}](
 [Id] [nvarchar](50) NOT NULL
 --,
 --[CreateTime] [datetime] NULL,
 --[ModifyTime] [datetime] NULL,
 --[CreateUserID] [nvarchar](50) NULL, 
 --[CreateUserName] [nvarchar](50) NULL, 
 --[ModifyUserID] [nvarchar](50) NULL, 
 --[ModifyUserName] [nvarchar](50) NULL, 
 --[OrderIndex] [float](50) NULL
 CONSTRAINT [PK_{0}] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
END".ReplaceArg(tableName) + "\r\n";
            
            string columnAndSubTableSql = GetFieldGeneralSql(tableName, moduleName, ctrlList);

            tableSql += columnAndSubTableSql;
            SqlHelper sqlHelper = new SqlHelper(moduleName);
            sqlHelper.ExcuteNoQuery(tableSql);
        }

        private string GetFieldGeneralSql(string tableName, string moduleName, IEnumerable<Dictionary<string, object>> ctrlAttrList)
        {
            string sql = "";
            string commonColSql = @"if not exists(select * from syscolumns where id=object_id('{0}') and name='{1}')
    alter table {0} add {1} {2}
else
    alter table {0} alter column {1} {2}";
            string commonDesSql = @"if not exists(select  fieldCode= a.name, description= g.[value] from sys.columns a join sys.extended_properties g 
 on (a.object_id = g.major_id and g.minor_id = a.column_id) where object_id =(select object_id from sys.tables where name = '{0}') and a.name='{1}')
    execute sp_addextendedproperty 'MS_Description', '{2}', 'user', dbo, 'table', '{0}', 'column', '{1}'
else
    execute sp_updateextendedproperty N'MS_Description', '{2}', N'user', N'dbo', N'Table', {0}, N'column' , {1}";

            foreach (var ctrlAttr in ctrlAttrList)
            {
                if (ctrlAttr.GetValue("FieldName") == "Id")
                    continue;

                //子表
                if (ctrlAttr.GetValue("CtrlType") == ControlType.SubDataGrid.ToString())
                {
                    var subTableName = ctrlAttr.GetValue("FieldName");

                    string tableSql = @"IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{0}]') AND type in (N'U'))
BEGIN
CREATE TABLE [{0}](
 [Id] [nvarchar](50) NOT NULL,
 [{1}Id] [nvarchar](50) NULL,
 [CreateTime] [datetime] NULL,
 [ModifyTime] [datetime] NULL,
 [CreateUserID] [nvarchar](50) NULL, 
 [CreateUserName] [nvarchar](50) NULL, 
 [ModifyUserID] [nvarchar](50) NULL, 
 [ModifyUserName] [nvarchar](50) NULL, 
 [OrderIndex] [float](50) NULL
 CONSTRAINT [PK_{0}] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [{0}]  WITH CHECK ADD  CONSTRAINT [FK_{0}_{1}] FOREIGN KEY([{1}Id])
REFERENCES [{1}] ([Id])
ON DELETE CASCADE
ALTER TABLE [{0}] CHECK CONSTRAINT [FK_{0}_{1}]
END".ReplaceArg(subTableName, tableName);

                    sql += tableSql + "\r\n";

                    var subCtrlAttr = ctrlAttr.GetValue("Detail").JsonToDictionary();
                    var subGridCtrlAttrList = subCtrlAttr.GetValue("ColumnSetting").JsonToDictionaryList();                    
                    foreach (var subGridCtrlAttr in subGridCtrlAttrList)
                    {
                        //开发级字段已经通过ef机制在数据库形成对应列,因此跳过
                        if (subGridCtrlAttr.GetValue("IsDevelopField") == "true")
                            continue;
                        if (subGridCtrlAttr.GetValue("FieldName") == "Id")
                            continue;

                        //字段名
                        string fieldName = subGridCtrlAttr.GetValue("FieldName");
                        //字段数据类型
                        string fieldType = subGridCtrlAttr.GetValue("FieldType");
                        //字段描述
                        string describ = subGridCtrlAttr.GetValue("ColumnName");

                        sql += string.Format(commonColSql, subTableName, fieldName, fieldType) + "\r\n";
                        sql += string.Format(commonDesSql, subTableName, fieldName, describ) + "\r\n";
                    }
                }
                else
                {
                    //开发级字段已经通过ef机制在数据库形成对应列,因此跳过
                    if (ctrlAttr.GetValue("IsDevelopField") == "true")
                        continue;

                    //字段名
                    string fieldName = ctrlAttr.GetValue("FieldName");
                    //字段数据类型
                    string fieldType = ctrlAttr.GetValue("FieldType");
                    //字段描述
                    string describ = ctrlAttr.GetValue("ColumnName");

                    sql += string.Format(commonColSql, tableName, fieldName, fieldType) + "\r\n";
                    sql += string.Format(commonDesSql, tableName, fieldName, describ) + "\r\n";
                }
            }

            var dicList = SqlHelper.GetColumnNameWithType(moduleName, tableName);
            foreach (var dic in dicList)
            {
                if (!ctrlAttrList.Any(a => a.GetValue("FieldName") == dic.GetValue("Name")))
                {
                    sql += "alter table {0} drop column {1} \r\n".ReplaceArg(tableName, dic.GetValue("Name"));
                }
            }

            return sql;
        }
        #endregion

        #region 数据源
        public ActionResult DataSource()
        {
            var list = WebConfigHelper.GetDBNames();
            var resList = new List<dynamic>();
            foreach(var item in list)
            {
                resList.Add(new { text = item, value = item });
            }
            ViewBag.DBNames = resList.ToJson();
            return View();
        }

        public JsonResult SaveDataSourceSetting(string formId, string data)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            cForm.DataSourceSetting = data;
            bool res = UnitOfWork.Commit();
            return Json(res);
        }

        public JsonResult GetDataSourceSetting(string formId)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            return Json(cForm.DataSourceSetting.JsonToDictionaryList());
        }
        #endregion

        #region 布局(Layout)
        public ActionResult Layout()
        {
            return View();
        }
        [ValidateInput(false)]
        public JsonResult SaveLayout(string formId, string html)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            cForm.LayOutSetting = Server.HtmlEncode(html);
            bool res = UnitOfWork.Commit();
            return Json(res);
        }
        public JsonResult GetLayout(string formId)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            return Json(Server.HtmlDecode(cForm.LayOutSetting ?? ""));
        }
        public JsonResult CreateLayout(string formId, string layoutType)
        {
            formId.CheckNotNullOrEmpty("formId");
            FormConfig cForm = UnitOfWork.GetByKey<FormConfig>(formId);
            cForm.CheckNotNull("FormConfig");
            var ctrlList = cForm.GetCtrlAttrList();
            StringBuilder formHtmlSB = new StringBuilder();

            //title
            formHtmlSB.Append("<div style='font-size:20px;width:100%;text-align:center;margin-top:10px'><strong>{0}</strong></div>".ReplaceArg(cForm.Name));

            //visible dom
            var withCtrlList = ctrlList.Where(a => a.GetValue("CtrlType") != ControlType.HiddenInput.ToString()).ToList();

            var groupSettingStr = cForm.GroupSetting;
            List<Dictionary<string, object>> groupSettingDicList = new List<Dictionary<string, object>>();

            if (!string.IsNullOrEmpty(groupSettingStr))
            {
                groupSettingDicList = groupSettingStr.JsonToDictionaryList();

                var tabGroupList = groupSettingDicList.Where(a => a.GetValue("ShowInTab") == "是");
                bool isTabHtmlAdded = false;
                //控件设置的组在控件组定义中的                
                foreach (var group in groupSettingDicList)
                {
                    //在组设置中第一次出现tab类组的作为其排序位置
                    if (group.GetValue("ShowInTab") == "是" && !isTabHtmlAdded)
                    {
                        formHtmlSB.Append(GetTabHtml(tabGroupList, withCtrlList, layoutType));
                        isTabHtmlAdded = true;
                    }
                    else if (group.GetValue("ShowInTab") != "是")
                    {
                        formHtmlSB.Append(GetGroupHtml(group.GetValue("Name"), withCtrlList, layoutType));
                    }
                }
            }

            //控件设置的组不在控件组定义中的
            var noInGroupSettingCtrlList = withCtrlList.Where(a => !groupSettingDicList.Any(b => b.GetValue("Name") == a.GetValue("Group")));
            //ctrl group
            var groupList = noInGroupSettingCtrlList.GroupBy(a => a.GetValue("Group")).Select(a => a.First()).Select(a => a.GetValue("Group"));
            foreach (var group in groupList)
            {
                formHtmlSB.Append(GetGroupHtml(group, withCtrlList, layoutType));
            }

            return Json(formHtmlSB.ToString());
        }

        private string GetGroupHtml(string groupName, IEnumerable<Dictionary<string, object>> dicList, string layoutType, bool needTitle = true)
        {
            StringBuilder formHtmlSB = new StringBuilder();
            var groupCtrlList = dicList.Where(a => a.GetValue("Group") == groupName).ToArray();

            int ctrlCount = groupCtrlList.Count();
            double dCol = 0;
            double.TryParse(layoutType, out dCol);
            if (dCol == 0)
                return "";

            double tmp = ctrlCount / dCol;
            int rowCount = Convert.ToInt32(Math.Ceiling(tmp));
            if (rowCount == 0)
                return "";

            double leftTdWithPercent = 15;
            double rightTdWithPercent = Math.Round(100 / dCol, 2) - 15;
            if (rightTdWithPercent < 0)
            {
                rightTdWithPercent = leftTdWithPercent = Math.Round(100 / Convert.ToDouble(2 * dCol), 0);
            }

            formHtmlSB.Append("<table class='groupTable'>");
            //title
            if (needTitle && !string.IsNullOrEmpty(groupName))
                formHtmlSB.Append(string.Format("<tr><td colspan='{0}' class='title'>{1}</td></tr>", 2 * dCol, groupName));

            //row
            int ctrlIndex = 0;
            for (int i = 0; i < rowCount; i++)
            {
                formHtmlSB.Append("<tr>");
                for (int j = 0; j < dCol; j++)
                {
                    string ctrlColName = "";
                    if (ctrlIndex < groupCtrlList.Count())
                    {
                        var ctrl = groupCtrlList[ctrlIndex];
                        ctrlColName = ctrl.GetValue("ColumnName");
                        if (string.IsNullOrEmpty(ctrlColName))
                        {
                            ctrlColName = ctrl.GetValue("FieldName");
                        }
                    }

                    //left
                    formHtmlSB.Append(string.Format("<td style='width:{0}%'>{1}</td>", leftTdWithPercent,
                        string.IsNullOrEmpty(ctrlColName) ? "" : (ctrlColName + ":")));
                    //right
                    formHtmlSB.Append(string.Format("<td style='width:{0}%'>{1}</td>", rightTdWithPercent,
                        string.IsNullOrEmpty(ctrlColName) ? "" : ("{" + ctrlColName + "}")));
                    ctrlIndex++;
                }
                formHtmlSB.Append("</tr>");
            }
            formHtmlSB.Append("</table>");

            return formHtmlSB.ToString();
        }

        private string GetTabHtml(IEnumerable<Dictionary<string, object>> groupList, IEnumerable<Dictionary<string, object>> ctrlList, string layoutType)
        {
            StringBuilder formHtmlSB = new StringBuilder();
            if (groupList.Count() > 0)
            {
                formHtmlSB.Append("<div style='padding:10px'><div class='easyui-tabs' id='mainTab' style='width:100%;height:250px;'>");
                foreach (var group in groupList)
                {
                    string contentHtml = GetGroupHtml(group.GetValue("Name"), ctrlList, layoutType, false);
                    if (!string.IsNullOrEmpty(contentHtml))
                        formHtmlSB.Append("<div data-options='border:false' title='{0}'><div style='padding:10px'>{1}</div></div>".ReplaceArg(group.GetValue("Name"), contentHtml));
                }
                formHtmlSB.Append("</div>");
            }
            return formHtmlSB.ToString();
        }
        #endregion
    }
}
